package com.lin.netty.improve.粘包与半包;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.Random;

/**
 * LengthFieldBasedFrameDecoder netty中提供的一个消息入站处理器，用于分隔包含消息的长度头部和消息实体内容的消息
 * lengthFieldOffset   = 1 (= the length of HDR1)         长度偏移量，从一个字节后开始读取长度
 * lengthFieldLength   = 2                                长度的字节数，2个字节，这里的结果是0x000C=12，表示消息内容有12个字节
 * lengthAdjustment    = 1 (= the length of HDR2)         长度调整，就是要跳过1个字节的HDR2开始读取12个字节消息内容
 * initialBytesToStrip = 3 (= the length of HDR1 + LEN)   最后要剔除的字节数，3个字节，剔除掉HDR1 + LEN
 * <p>
 * BEFORE DECODE (16 bytes)                       AFTER DECODE (13 bytes)
 * +------+--------+------+----------------+      +------+----------------+
 * | HDR1 | Length | HDR2 | Actual Content |----->| HDR2 | Actual Content |
 * | 0xCA | 0x000C | 0xFE | "HELLO, WORLD" |      | 0xFE | "HELLO, WORLD" |
 * +------+--------+------+----------------+      +------+----------------+
 */
@Slf4j
public class Client4 {
    public static void main(String[] args) {
        NioEventLoopGroup workers = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(workers)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ch.pipeline().addLast("logging", new LoggingHandler());

                            ch.pipeline().addLast("o1", new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) throws Exception { // 连接建立成功后，会触发Active事件
                                    // 想给服务器发10次消息
                                    Random random = new Random();
                                    int msg_len;
                                    char c = 'a';
                                    ByteBuf msg = ctx.alloc().buffer();
                                    msg.writeInt(17);
                                    for (int i = 0; i < 17; i++) {
                                        msg.writeByte(c);
                                    }
                                    ctx.writeAndFlush(msg);
          /*                          for (int i = 0; i < 10; i++) {
                                        ByteBuf msg = ctx.alloc().buffer();
                                        msg_len = random.nextInt(256) + 1;
                                        msg.writeInt(msg_len);
                                        for (int j = 0; j < msg_len; j++) {
                                            msg.writeByte(c);
                                        }
                                        c++;
                                        ctx.writeAndFlush(msg); // 这里也会调用ByteBuf的release方法
                                    }*/
                                }
                            });
                        }
                    });

            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 1122).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("client error", e);
        } finally {
            workers.shutdownGracefully();
        }

    }
}
